package com.example.demo.excel;

import com.xctech.xcexcel.annotaion.ExcelColumn;
import com.xctech.xcexcel.config.TableConfig;
import com.xctech.xcexcel.entity.CellPos;
import com.xctech.xcexcel.entity.CloumnTitle;
import com.xctech.xcexcel.entity.ColumnAttribute;
import com.xctech.xcexcel.entity.GroupColumnPos;
import com.xctech.xcexcel.entity.TableSum;
import com.xctech.xcexcel.entity.TableTitle;
import com.xctech.xcexcel.entity.align.NumberAlign;
import com.xctech.xcexcel.entity.align.WordAlign;
import com.xctech.xcexcel.exception.XcExcelException;
import com.xctech.xcexcel.hook.ExcelCellValue;
import com.xctech.xcexcel.model.ExcelTable;
import com.xctech.xcexcel.utils.CellStyleUtil;
import com.xctech.xcexcel.utils.DataUtil;
import jdk.nashorn.internal.ir.debug.ObjectSizeCalculator;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.apache.poi.ss.usermodel.Cell;
import org.apache.poi.ss.usermodel.CellStyle;
import org.apache.poi.ss.usermodel.ClientAnchor;
import org.apache.poi.ss.usermodel.Comment;
import org.apache.poi.ss.usermodel.CreationHelper;
import org.apache.poi.ss.usermodel.Drawing;
import org.apache.poi.ss.usermodel.HorizontalAlignment;
import org.apache.poi.ss.usermodel.IndexedColors;
import org.apache.poi.ss.usermodel.RichTextString;
import org.apache.poi.ss.usermodel.Row;
import org.apache.poi.ss.usermodel.Sheet;
import org.apache.poi.ss.usermodel.Workbook;
import org.apache.poi.ss.usermodel.WorkbookFactory;
import org.apache.poi.ss.util.CellRangeAddress;
import org.apache.poi.ss.util.CellReference;
import org.apache.poi.xssf.streaming.SXSSFWorkbook;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;

import java.io.FileOutputStream;
import java.io.InputStream;
import java.io.OutputStream;
import java.lang.reflect.Field;
import java.math.BigDecimal;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;


/**
 * @param <T>
 * @Description 简单表格
 * @Auther duanhp
 * @Date 2021-11-15
 */

@Slf4j
public class StdTable<T> implements ExcelTable<T> {

    Class<T> clazz;

    private TableConfig tableConfig = new TableConfig();

    private ExcelCellValue excelCellValue;

    public StdTable(Class<T> clazz) {
        this.clazz = clazz;
    }

    public ExcelCellValue getExcelCellValue() {
        return excelCellValue;
    }

    public void setExcelCellValue(ExcelCellValue excelCellValue) {
        this.excelCellValue = excelCellValue;
    }


    /**
     * @param columnName
     * @return
     */
    private boolean ifColumnExport(String columnName) {
        if (ifFilterColumn(columnName)) {
            return false;
        }
        return true;
    }

    private boolean ifFilterColumn(String columnName) {
        List<String> filterColumns = tableConfig.getFilterColumns();
        if (filterColumns == null) {
            return false;
        }
        if (filterColumns.indexOf(columnName) >= 0) {
            return true;
        }
        return false;
    }


    private List<ColumnAttribute> sortByGroup(List<ColumnAttribute> fields) {
        List<ColumnAttribute> sortFields = new ArrayList<>();
        Map<String, Boolean> groupMap = new HashMap<>();
        for (ColumnAttribute attribute : fields) {
            String groupName = attribute.getGroupName();
            if (StringUtils.isEmpty(groupName)) {
                sortFields.add(attribute);
            } else {
                Boolean isExist = groupMap.get(groupName);
                if (isExist != null && isExist) {
                    continue;
                }
                groupMap.put(groupName, true);
                for (ColumnAttribute columnAttribute : fields) {
                    String gname = columnAttribute.getGroupName();
                    if (groupName.equals(gname)) {
                        sortFields.add(columnAttribute);
                    }
                }
            }
        }
        return sortFields;
    }


    /**
     * 获取所有字段
     *
     * @param clazz
     * @param fields
     * @return
     */
    private List<ColumnAttribute> getMappedFiled(Class clazz, List<ColumnAttribute> fields) {
        if (fields == null) {
            fields = new ArrayList<ColumnAttribute>();
        }
        Field[] allFields = clazz.getDeclaredFields();
        for (Field field : allFields) {
            if (field.isAnnotationPresent(ExcelColumn.class)) {
                ExcelColumn column = field.getAnnotation(ExcelColumn.class);
                String columnName = getColumnName(column, field);
                if (ifColumnExport(columnName)) {
                    ColumnAttribute columnAttribute = new ColumnAttribute();
                    columnAttribute.setDisplayName(columnName);
                    columnAttribute.setField(field);
                    columnAttribute.setGroupName(column.group());
                    columnAttribute.setSuffix(column.suffix());
                    columnAttribute.setColumn(column);
                    columnAttribute.setColumnWidth(column.width());
                    fields.add(columnAttribute);
                }
            }
        }
        if (clazz.getSuperclass() != null
                && !clazz.getSuperclass().equals(Object.class)) {
            getMappedFiled(clazz.getSuperclass(), fields);
        }
        List<CloumnTitle> columns = tableConfig.getColumns();
        if (columns != null && !columns.isEmpty()) {
            List<ColumnAttribute> displayFields = new ArrayList<ColumnAttribute>();
            for (CloumnTitle title : columns) {
                for (ColumnAttribute columnAttribute : fields) {
                    String fieldName = title.getFieldName();
                    if (StringUtils.isEmpty(fieldName)) {
                        continue;
                    }
                    Field field = columnAttribute.getField();
                    if (field == null) {
                        continue;
                    }
                    if (fieldName.toUpperCase().equals(field.getName().toUpperCase())) {
                        String disName = DataUtil.defValue(title.getCaption(), columnAttribute.getDisplayName());
                        columnAttribute.setDisplayName(disName);
                        columnAttribute.setGroupName(title.getGroupName());
                        displayFields.add(columnAttribute);
                    }
                }
            }
            if (!displayFields.isEmpty()) {
                return displayFields;
            }
        }
        fields = sortByGroup(fields);
        return fields;
    }

    /**
     * 获取列名称
     *
     * @param column
     * @param field
     * @return
     */
    private String getColumnName(ExcelColumn column, Field field) {
        String title = field.getName();
        if (column != null) {
            title = column.value();
            if (StringUtils.isEmpty(title)) {
                title = column.name();
            }
        }
        return title;
    }

    /**
     * 获取批注
     *
     * @param wb
     * @param sheet
     * @param column
     * @return
     */
    private Comment getComment(Workbook wb, Sheet sheet, ExcelColumn column) {
        String prompt = column.prompt();
        if (StringUtils.isEmpty(prompt)) {
            return null;
        }
        CreationHelper factory = wb.getCreationHelper();
        ClientAnchor anchor = factory.createClientAnchor();
        Drawing<?> drawing = sheet.createDrawingPatriarch();
        Comment comment1 = drawing.createCellComment(anchor);
        RichTextString str1 = factory.createRichTextString(prompt);
        comment1.setString(str1);
        comment1.setAuthor("system");
        return comment1;
    }

    /**
     * 使用默认的样式修正
     *
     * @param defCellType
     * @return
     */
    private com.xctech.xcexcel.entity.style.CellStyle getDefCellStyle(com.xctech.xcexcel.entity.style.CellStyle defCellType) {
        if (defCellType != null) {
            return defCellType;
        }
        com.xctech.xcexcel.entity.style.CellStyle defCellType1 = new com.xctech.xcexcel.entity.style.CellStyle();
        defCellType1.setBackgroundColor(null);
        defCellType1.setFillPattern(null);
        return defCellType1;
    }

    /**
     * @param wb
     * @param defCellType
     * @return
     */
    private CellStyle getSumCellStyle(ExcelColumn column, Workbook wb, CreationHelper createHelper,
                                      com.xctech.xcexcel.entity.style.CellStyle defCellType, Field field) {
        if (defCellType == null) {
            defCellType = new com.xctech.xcexcel.entity.style.CellStyle();
            defCellType.getFontStyle().setBold(true);
        }
        CellStyle cellStyle = wb.createCellStyle();
        //data format
        if (column != null && !StringUtils.isEmpty(column.format())) {
            cellStyle.setDataFormat(
                    createHelper.createDataFormat().getFormat(column.format()));
        }
        CellStyleUtil cellStyleUtil = new CellStyleUtil(defCellType);
        cellStyleUtil.fillCellStyle(cellStyle, wb);
        //..
        handleDataAlign(cellStyle, field);
        return cellStyle;
    }

    /**
     * 获取表格标题样式
     *
     * @param wb
     * @param titleCellStyle
     * @return
     */
    protected CellStyle getTitleCellStyle(Workbook wb, com.xctech.xcexcel.entity.style.CellStyle titleCellStyle) {
        CellStyle cellStyle = wb.createCellStyle();
        com.xctech.xcexcel.entity.style.CellStyle cellStyle1 = getDefCellStyle(titleCellStyle);
        if (!cellStyle1.equals(titleCellStyle)) {
            cellStyle1.getFontStyle().setBold(true);
        }
        CellStyleUtil cellStyleUtil = new CellStyleUtil(cellStyle1);
        cellStyleUtil.fillCellStyle(cellStyle, wb);
        return cellStyle;
    }


    private boolean isNumber(Class value) {
        return value == Long.class || value == Integer.class || value == Double.class
                || value == Float.class || value == Short.class || value == Byte.class
                || value == BigDecimal.class;
    }

    private void handleDataAlign(CellStyle cellStyle, Field field) {
        Class value = field.getType();
        if (isNumber(value)) {
            NumberAlign numberAlign = tableConfig.getNumberAlign();
            if (numberAlign != null) {
                cellStyle.setAlignment(numberAlign.getHalign());
            }
        } else {
            WordAlign wordAlign = tableConfig.getWordAlign();
            if (wordAlign != null) {
                cellStyle.setAlignment(wordAlign.getHalign());
            }
        }
    }

    /**
     * 获取表头的样式
     *
     * @param column
     * @param wb
     * @param createHelper
     * @return
     */
    protected CellStyle getHeaderCellStyle(ExcelColumn column, Workbook wb, CreationHelper createHelper, Field field) {
        CellStyle cellStyle = wb.createCellStyle();
        com.xctech.xcexcel.entity.style.CellStyle cellStyle1 = getDefCellStyle(tableConfig.getHeaderStyle());
        if (!cellStyle1.equals(tableConfig.getHeaderStyle())) {
            cellStyle1.getFontStyle().setBold(true);
            if (cellStyle1.getBackgroundColor().equals(IndexedColors.WHITE)) {
                cellStyle1.setBackgroundColor(IndexedColors.GREY_25_PERCENT);
            }
        }
        CellStyleUtil cellStyleUtil = new CellStyleUtil(cellStyle1);
        cellStyleUtil.fillCellStyle(cellStyle, wb);
        //..
        handleDataAlign(cellStyle, field);
        return cellStyle;
    }


    /**
     * 获取表格数据的样式
     *
     * @param column
     * @param wb
     * @param createHelper
     * @return
     */
    protected CellStyle getDataCellStyle(ExcelColumn column, Workbook wb, CreationHelper createHelper, Field field) {
        CellStyle cellStyle = wb.createCellStyle();
        //data format
        if (column != null && !StringUtils.isEmpty(column.format())) {
            cellStyle.setDataFormat(
                    createHelper.createDataFormat().getFormat(column.format()));
        }
        com.xctech.xcexcel.entity.style.CellStyle cellStyle1 = getDefCellStyle(tableConfig.getDataStyle());
        cellStyle1.setBackgroundColor(null);
        cellStyle1.setFillPattern(null);
        CellStyleUtil cellStyleUtil = new CellStyleUtil(cellStyle1);
        cellStyleUtil.fillCellStyle(cellStyle, wb);
        //..
        handleDataAlign(cellStyle, field);
        return cellStyle;
    }

    /**
     * @param cell
     * @param dataValue
     * @return
     */
    protected Object getCellValue(Cell cell, Field field, Object dataValue, T dataObj) {
        if (excelCellValue == null) {
            return dataValue;
        }
        return excelCellValue.setCellValue(cell, field.getName(), dataValue, dataObj);
    }

    private int calcNumberLength(String value) {
        try {
            String val = value;
            int ilen = val.getBytes("GBK").length;
            int ipos = val.indexOf(".");
            if (ipos >= 0) {
                String val1 = val.substring(ipos + 1);
                int ilen1 = val1.getBytes("GBK").length;
                if (ilen1 > 4) {
                    ilen = ilen - ilen1 + 4;
                }
            }
            if (ilen > 24) {
                return 24;
            }
            int isize = ilen + 8;
            if (isize > 24) {
                return 24;
            }
            return isize;
        } catch (Exception e) {

        }
        return 15;
    }

    /**
     * 赋值
     *
     * @param cell
     * @param field
     * @param data
     * @throws IllegalAccessException
     */
    private void setCellValue(Cell cell, Field field, T data, ColumnAttribute attribute) {
        try {
            Object vo = field.get(data);
            vo = getCellValue(cell, field, vo, data);
            if (vo == null) {
                cell.setCellValue("");
                if (StringUtils.isNotEmpty(tableConfig.getNullDisplayChar())) {
                    cell.setCellValue(tableConfig.getNullDisplayChar());
                }
                return;
            }
            if (StringUtils.isNotEmpty(attribute.getSuffix())) {
                String value = vo.toString();
                if (!"--".equals(value) && !"-".equals(value)) {
                    value = value + "" + attribute.getSuffix();
                }
                cell.setCellValue(value);
                //..
                calcColumnWidth(attribute, calcNumberLength(value));
                return;
            }
            if (vo instanceof String) {
                String value = (String) vo;
                cell.setCellValue(value);
                calcColumnWidth(attribute, value);
                return;
            }
            if (vo instanceof Double) {
                Double dvalue = (Double) vo;
                cell.setCellValue(dvalue);
                String value = dvalue.toString();
                calcColumnWidth(attribute, calcNumberLength(value));
                return;
            }
            if (vo instanceof Long) {
                Long dvalue = (Long) vo;
                cell.setCellValue((Long) vo);
                String value = dvalue.toString();
                calcColumnWidth(attribute, calcNumberLength(value));
                return;
            }
            if (vo instanceof LocalDateTime) {
                LocalDateTime dvalue = (LocalDateTime) vo;
                cell.setCellValue((LocalDateTime) vo);
                String value = dvalue.toString();
                calcColumnWidth(attribute, 24);
                return;
            }
            if (vo instanceof Date) {
                Date dvalue = (Date) vo;
                cell.setCellValue((Date) vo);
                String value = dvalue.toString();
                calcColumnWidth(attribute, 24);
                return;
            }
            if (vo instanceof Integer) {
                Integer dvalue = (Integer) vo;
                cell.setCellValue((Integer) vo);
                String value = dvalue.toString();
                calcColumnWidth(attribute, calcNumberLength(value));
                return;
            }
            if (vo instanceof Short) {
                Short dvalue = (Short) vo;
                cell.setCellValue((Short) vo);
                String value = dvalue.toString();
                calcColumnWidth(attribute, calcNumberLength(value));
                return;
            }
            if (vo instanceof Float) {
                Float dvalue = (Float) vo;
                cell.setCellValue((Float) vo);
                String value = dvalue.toString();
                calcColumnWidth(attribute, calcNumberLength(value));
                return;
            }
            if (vo instanceof BigDecimal) {
                BigDecimal v1 = (BigDecimal) vo;
                cell.setCellValue(v1.doubleValue());
                String value = v1.toString();
                calcColumnWidth(attribute, calcNumberLength(value));
                return;
            }
            if (vo instanceof LocalDate) {
                LocalDate dvalue = (LocalDate) vo;
                cell.setCellValue((LocalDate) vo);
                String value = dvalue.toString();
                calcColumnWidth(attribute, 24);
                return;
            }
            // 如果数据存在就填入,不存在填入空格.
            String value = String.valueOf(vo);
            cell.setCellValue(value);
            calcColumnWidth(attribute, value);
        } catch (Exception e) {
            throw new XcExcelException(e);
        }
    }

    /**
     * 修正序号
     *
     * @param column
     * @param index
     * @return
     */
    private Integer getColumnIndex(ExcelColumn column, Integer index) {
        if (column.index() >= 0) {
            return column.index();
        }
        return index;
    }

    /**
     * 获取sheet的名称
     *
     * @param
     * @return
     */
    private String getSheetName() {
        if (tableConfig != null) {
            return tableConfig.getSheetName();
        }
        return "sheet1";
    }

    /**
     * 获取表格输出的位置
     *
     * @return
     */
    protected CellPos getTablePos() {
        if (tableConfig != null && tableConfig.getPosition() != null) {
            return tableConfig.getPosition();
        }
        CellPos position = new CellPos(0, 0);
        return position;
    }

    protected Integer getColumnWidth(ExcelColumn column) {
        if (tableConfig != null && tableConfig.getColumnWidth() >= 0) {
            return tableConfig.getColumnWidth();
        }
        if (column != null) {
            return column.width();
        }
        return -1;
    }

    private int getInnerColumnWidth(ExcelColumn column) {
        Integer width = getColumnWidth(column);
        return (int) ((width + 0.72) * 256);
    }

    private int getInnerColumnWidth(ExcelColumn column, ColumnAttribute columnAttribute) {
        Integer width = getColumnWidth(column);
        if (columnAttribute.getColumnWidth() > width) {
            width = columnAttribute.getColumnWidth();
        }
        if (width > 200) {
            width = 200;
        }
        return (int) ((width) * 256);
    }

    private int getRowHeight() {
        if (tableConfig != null && tableConfig.getRowHeight() > 0) {
            return tableConfig.getRowHeight();
        }
        return 20;
    }

    public TableConfig getTableConfig() {
        return tableConfig;
    }

    public void setTableConfig(TableConfig tableConfig) {
        if (tableConfig == null) {
            this.tableConfig = new TableConfig();
            return;
        }
        this.tableConfig = tableConfig;
    }


    /**
     * 生成标题
     *
     * @param wb
     * @param sheet
     * @param irow
     * @param icol
     * @param allFields
     * @return
     */
    public int makeTitle(Workbook wb, Sheet sheet, int irow, int icol, List<ColumnAttribute> allFields) {
        TableTitle tableTitle = this.tableConfig.getTableTitle();
        if (tableTitle == null) {
            return irow;
        }
        //..
        if (StringUtils.isEmpty(tableTitle.getTitle())) {
            return irow;
        }
        int lastCol = icol + allFields.size();
        Row row = sheet.createRow(irow);
        Cell cell = row.createCell(icol);
        cell.setCellValue(tableTitle.getTitle());
        CellStyle cellStyle = getTitleCellStyle(wb, tableTitle.getTitleStyle());
        cell.setCellStyle(cellStyle);

        for (int i = 1; i < allFields.size(); i++) {
            int colNo = i + icol;
            Cell cell1 = row.createCell(colNo);
            cell1.setCellValue("");
            cell1.setCellStyle(cellStyle);
        }
        sheet.addMergedRegion(new CellRangeAddress(
                irow, //first row (0-based)
                irow, //last row  (0-based)
                icol, //first column (0-based)
                lastCol - 1  //last column  (0-based)
        ));
        //..
        row.setHeightInPoints(tableTitle.getRowHeight());
        //..
        irow++;
        return irow;
    }

    /**
     * 合计
     *
     * @param sheet
     */
    public void makeSum(Workbook wb, Sheet sheet, CreationHelper createHelper,
                        int icol, int startRow, int endRow, List<ColumnAttribute> columnAttributes) {
        //..
        TableSum tableSum = this.tableConfig.getTableSum();
        if (tableSum == null) {
            return;
        }

        int irow = endRow + 1;
        Row row = sheet.createRow(irow);
        for (int i = 0; i < columnAttributes.size(); i++) {
            ColumnAttribute attribute = columnAttributes.get(i);
            Field field = attribute.getField();
            ExcelColumn column = field.getAnnotation(ExcelColumn.class);
            CellStyle cellStyle = getSumCellStyle(column, wb, createHelper, tableSum.getSumStyle(), field);
            int colNo = icol + i;
            Cell cell = row.createCell(colNo);
            if (!column.isSum()) {
                cell.setCellValue("");
                if (colNo == icol) {
                    cell.setCellValue("合计");
                }
                cell.setCellStyle(cellStyle);
                continue;
            }
            //..
            String colString = CellReference.convertNumToColString(colNo);
            String sumString = "SUM(" + colString + (startRow + 1) + ":" + colString + (endRow + 1) + ")";
            cell.setCellFormula(sumString);
            cell.setCellStyle(cellStyle);
        }
    }


    private Sheet getSheet(Workbook wb) {
        String sheetName = getSheetName();
        Sheet sheet = wb.getSheet(sheetName);
        if (sheet == null) {
            sheet = wb.createSheet(sheetName);
            sheet.setDefaultRowHeightInPoints((short) 20);
        }
        return sheet;
    }


    private boolean isNeedGroup(List<ColumnAttribute> allFields) {
        for (ColumnAttribute columnAttribute : allFields) {
            if (StringUtils.isNotEmpty(columnAttribute.getGroupName())) {
                return true;
            }
        }
        return false;
    }

    private void adjustColumnWidthBySetting(Sheet sheet, int colNo, ColumnAttribute columnAttribute) {
        int colWidth = getInnerColumnWidth(columnAttribute.getColumn(), columnAttribute);
        if (colWidth > 0) {
            sheet.setColumnWidth(colNo, colWidth);
        } else {
            sheet.autoSizeColumn(colNo, true);
        }
    }

    private void calcColumnWidth(ColumnAttribute columnAttribute, int wordlength) {
        int temp = wordlength;
        if (tableConfig != null && tableConfig.getColumnWidth() > 0) {
            if (tableConfig.getColumnWidth() > wordlength) {
                temp = tableConfig.getColumnWidth();
            }
        }
        if (columnAttribute.getColumnWidth() < temp) {
            columnAttribute.setColumnWidth(temp);
        }
    }

    private void calcColumnWidth(ColumnAttribute columnAttribute, String data) {
        try {
            calcColumnWidth(columnAttribute, data.getBytes("GBK").length + 2);
        } catch (Exception e) {

        }
    }

    private int makeHeader(Workbook wb, Sheet sheet, CreationHelper createHelper, List<ColumnAttribute> allFields,
                           int irow, int icol) {

        int rowHeight = this.getRowHeight();

        Boolean isGroup = isNeedGroup(allFields);
        int newRow = irow;
        Row row = sheet.createRow(newRow);
        row.setHeightInPoints(rowHeight);

        Row row1 = row;
        if (isGroup) {
            newRow = newRow + 1;
            row1 = sheet.createRow(newRow);
            row1.setHeightInPoints(rowHeight);
        }

        Map<String, GroupColumnPos> gcpos = new HashMap<>();
        List<String> indexList = new ArrayList<>();

        //标题
        for (int i = 0; i < allFields.size(); i++) {
            //..
            ColumnAttribute attribute = allFields.get(i);
            Field field = attribute.getField();
            ExcelColumn column = field.getAnnotation(ExcelColumn.class);
            int colNo = icol + i;
            Cell cell = row.createCell(colNo);
            cell.setCellValue(attribute.getDisplayName());
            CellStyle titleStyle = getHeaderCellStyle(column, wb, createHelper, field);
            cell.setCellStyle(titleStyle);
            cell.setCellComment(getComment(wb, sheet, column));
            CellStyle dataStyle = getDataCellStyle(column, wb, createHelper, field);
            //调整列宽
            calcColumnWidth(attribute, attribute.getDisplayName());
            adjustColumnWidthBySetting(sheet, colNo, attribute);
            //..
            attribute.setTitleStyle(titleStyle);
            attribute.setDataStyle(dataStyle);
            //..
            if (isGroup) {
                Cell cell1 = row1.createCell(colNo);
                cell1.setCellValue(attribute.getDisplayName());
                CellStyle titleStyle1 = getHeaderCellStyle(column, wb, createHelper, field);
                cell1.setCellStyle(titleStyle1);
                cell1.setCellComment(getComment(wb, sheet, column));
                if (StringUtils.isEmpty(attribute.getGroupName())) {
                    sheet.addMergedRegion(new CellRangeAddress(
                            irow, //first row (0-based)
                            newRow, //last row  (0-based)
                            colNo, //first column (0-based)
                            colNo  //last column  (0-based)
                    ));
                    //调整列宽
                    calcColumnWidth(attribute, attribute.getDisplayName());
                    adjustColumnWidthBySetting(sheet, colNo, attribute);
                } else {
                    titleStyle.setAlignment(HorizontalAlignment.CENTER);
                    cell.setCellValue(attribute.getGroupName());
                    cell.setCellStyle(titleStyle);
                    GroupColumnPos groupColumnPos = gcpos.get(attribute.getGroupName());
                    if (groupColumnPos == null) {
                        groupColumnPos = new GroupColumnPos();
                        groupColumnPos.setName(attribute.getGroupName());
                        groupColumnPos.setStart(colNo);
                        groupColumnPos.setEnd(colNo);
                        gcpos.put(attribute.getGroupName(), groupColumnPos);
                        indexList.add(attribute.getGroupName());
                    } else {
                        groupColumnPos.setEnd(colNo);
                    }
                }

            }
        }
        if (!isGroup) {
            return newRow;
        }
        for (String groupName : indexList) {
            GroupColumnPos groupColumnPos = gcpos.get(groupName);
            if (groupColumnPos.getStart() == groupColumnPos.getEnd()) {
                continue;
            }
            sheet.addMergedRegion(new CellRangeAddress(
                    irow, //first row (0-based)
                    irow, //last row  (0-based)
                    groupColumnPos.getStart(), //first column (0-based)
                    groupColumnPos.getEnd()  //last column  (0-based)
            ));
        }
        return newRow;
    }


    private void adjustColumnWidth(Sheet sheet, int icol, List<ColumnAttribute> allFields) {
        for (int i = 0; i < allFields.size(); i++) {
            ColumnAttribute attribute = allFields.get(i);
            int colNo = icol + i;
            adjustColumnWidthBySetting(sheet, colNo, attribute);
        }
    }


    private void makeExcel(Workbook wb, List<T> list) {
        CreationHelper createHelper = wb.getCreationHelper();
        Sheet sheet = getSheet(wb);
        List<ColumnAttribute> allFields = getMappedFiled(clazz, null);
        if (allFields.isEmpty()) {
            throw new XcExcelException("未查询到导出的列");
        }
        CellPos cellPos = getTablePos();
        int irow = cellPos.getRow();
        int icol = cellPos.getCol();
        //生成标题
        irow = makeTitle(wb, sheet, irow, icol, allFields);
        List<ColumnAttribute> columnAttributes = allFields;
        //生成表头
        irow = makeHeader(wb, sheet, createHelper, allFields, irow, icol);
        //写数据
        int rowHeight = this.getRowHeight();
        int startNo = irow + 1;
        for (T data : list) {
            Row row1 = sheet.createRow(startNo);
            row1.setHeightInPoints(rowHeight);
            for (int i = 0; i < columnAttributes.size(); i++) {
                ColumnAttribute attribute = columnAttributes.get(i);
                Field field = attribute.getField();
                field.setAccessible(true);
                int colNo = icol + i;
                Cell cell = row1.createCell(colNo);
                CellStyle cellStyle = attribute.getDataStyle();
                cell.setCellStyle(cellStyle);
                setCellValue(cell, field, data, attribute);
            }
            startNo++;
        }
        //合计
        makeSum(wb, sheet, createHelper, icol, irow + 1, startNo - 1, columnAttributes);
        //自动调整列宽
        adjustColumnWidth(sheet, icol, columnAttributes);
    }


    private void writeExcel(Workbook wb, OutputStream fileOut, List<T> list) throws Exception {
        makeExcel(wb, list);
        //..
        wb.write(fileOut);
    }

    @Override
    public void export(OutputStream fileOut, List<T> list) {
        Workbook wb = new SXSSFWorkbook();
        try {
            try {
                writeExcel(wb, fileOut, list);
                log.info("对象大小：{}", ObjectSizeCalculator.getObjectSize(wb));
            } finally {
                wb.close();
            }
        } catch (Exception e) {
            throw new XcExcelException(e);
        }
    }

    @Override
    public void export(Workbook wb, List<T> list) {
        makeExcel(wb, list);
    }

    @Override
    public void export(InputStream fileIn, OutputStream fileOut, List<T> list) {
        try {
            Workbook wb = WorkbookFactory.create(fileIn);
            try {
                writeExcel(wb, fileOut, list);
            } finally {
                wb.close();
            }
        } catch (Exception e) {
            throw new XcExcelException(e);
        }
    }

    @Override
    public void export(String filename, List<T> list) {
        try {
            OutputStream fileOut = new FileOutputStream(filename);
            try {
                export(fileOut, list);
            } finally {
                fileOut.flush();
                fileOut.close();
            }
        } catch (Exception e) {
            throw new XcExcelException(e);
        }
    }
}
